Two Pointer
Patterns
Running from both ends of an array
- Having two pointers at left and right end of array, then moving them to the center while processing something with them.
When to use
This works particularly well for sorted array
Need to find a pair of values
Trapping Rain Water - https://leetcode.com/problems/trapping-rain-water/
- Have to be able to find out the mathematic equation for each position
- The remaining is just optimizing how to find maxLeft, maxRight in the most efficient way
def trap(self, height: List[int]) -> int:
# curTrap = min(left, right) - height[i]
left, right = 0, len(height) - 1
res = 0
leftMax, rightMax = 0, 0
while left < right:
if height[left] < height[right]:
leftMax = max(leftMax, height[left])
res += leftMax - height[left]
left += 1
else:
rightMax = max(rightMax, height[right])
res += rightMax - height[right]
right -= 1
return res
Fast and Slow Pointer
- Usually used in [[6. Linked List]] for cycle detection
Same Direction
- Both pointers move in the same direction, but at different paces or with different conditions.
When to use
- If need to process elements sequentially
- If need to modify array in-place
Merge 2 arrays
- Will be given 2 arrays or lists, then have to process them with individual pointers
https://leetcode.com/problems/add-strings
- Pretty good questions on practicing adding 2 string numbers
def addStrings(self, num1: str, num2: str) -> str:
l1, l2 = len(num1) - 1, len(num2) - 1
rem = 0
res = []
while l1 >= 0 or l2 >= 0 or rem:
val1 = int(num1[l1]) if l1 >= 0 else 0
val2 = int(num2[l2]) if l2 >= 0 else 0
total = val1 + val2 + rem
rem = total // 10
res.insert(0, str(total % 10))
l1 -= 1
l2 -= 1
return ''.join(res)
Variants
Next Permutation Theory
https://leetcode.com/problems/next-permutation
- This problem is not usual two pointer problem
- The only reason we call it two pointer is because we want to swap 2 value in place which we have to use 2 pointer
- Otherwise, this is a math problem
- The idea is similar to permute a number to get the next greater value
- First we have to find a value we want to swap and a second value to swap it with
- Then we sort the rest to ensure that we have smallest right part possible
- [[Useful math#^2b285a | Next greater number theory]]
def nextPermutation(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
swapLeft = len(nums) - 2
while swapLeft >= 0 and nums[swapLeft] >= nums[swapLeft + 1]:
swapLeft -= 1
if swapLeft < 0:
return nums.reverse()
swapRight = nums[swapLeft+1:].index(max(nums[swapLeft+1:]))
swapRightVal = float('inf')
for i in range(swapLeft+1, len(nums)):
if nums[i] > nums[swapLeft] and nums[i] < swapRightVal:
swapRightVal = nums[i]
swapRight = i
nums[swapLeft], nums[swapRight] = nums[swapRight], nums[swapLeft]
nums[swapLeft+1:] = sorted(nums[swapLeft+1:])
https://leetcode.com/problems/next-greater-element-iii
- Same as above
def nextGreaterElement(self, n: int) -> int:
n = list([int(i) for i in str(n)])
swapLeft = len(n) - 2
while swapLeft >= 0 and n[swapLeft] >= n[swapLeft+1]:
swapLeft -= 1
if swapLeft < 0:
return -1
swapRight = len(n) - 1
swapRightVal = float('inf')
for i in range(swapLeft+1, len(n)):
if n[i] > n[swapLeft] and n[i] < swapRightVal:
swapRight = i
swapRightVal = n[i]
n[swapLeft], n[swapRight] = n[swapRight], n[swapLeft]
n[swapLeft+1:] = sorted(n[swapLeft+1:])
res = int(''.join([str(i) for i in n]))
if res > 2**31 - 1:
return -1
return res